﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Facet.Combinatorics;

namespace F1MinEffortCalc
{
    public class CalculateException : Exception
    {
        public CalculateException(string message)
            : base(message)
        {
        }
    }

    public class Driver
    {
        public int Standing { get; set; }
        public string Name { get; private set; }
        public int Points { get; set; }

        public Driver(int standing, string name, int points)
        {
            this.Standing = standing;
            this.Name = name;
            this.Points = points;
        }
    }

    public class PointSet
    {
        public List<int> Positions { get; set;}
        public int Points { get; set; }

        public PointSet(List<int> positions)
        {
            this.Positions = positions;
            foreach (int position in this.Positions)
            {
                this.Points += Calculator.PointsAwarded[position];
            }
        }
    }

    public class Calculator
    {
        public static readonly Dictionary<int, int> PointsAwarded = new Dictionary<int, int>()
        {
            { 1, 25 },
            { 2, 18 },
            { 3, 15 },
            { 4, 12 },
            { 5, 10 },
            { 6, 8 },
            { 7, 6 },
            { 8, 4 },
            { 9, 2 },
            { 10, 1 }
        };

        public const int RacesToGo = 6;

        public List<Driver> CurrentStandings = new List<Driver>()
        {
            new Driver(1, "Alonso", 194),
            new Driver(2, "Vettel", 165),
            new Driver(3, "Räikkönen", 149),
            new Driver(4, "Hamilton", 142),
            new Driver(5, "Webber", 132),
            new Driver(6, "Button", 119),
            new Driver(7, "Rosberg", 93),
            new Driver(8, "Grosjean", 82),
            new Driver(9, "Pérez", 66),
            new Driver(10, "Massa", 51),
        };

        public Calculator()
        {
        }

        public void TrytoWin(string driver)
        {
            Driver ourDriver = CurrentStandings.FirstOrDefault(x => x.Name == driver);
            if (ourDriver != null)
            {
                Driver highestDriver = CurrentStandings.OrderByDescending(x => x.Points).FirstOrDefault();
                if (ourDriver != highestDriver)
                {
                    int pointsDifference = highestDriver.Points - ourDriver.Points;
                    if (pointsDifference < (PointsAwarded[1] * RacesToGo))
                    {
                        var driversInBetween = CurrentStandings.Where(x => x.Standing < ourDriver.Standing && x.Standing > highestDriver.Standing);
                        if (driversInBetween.Count() == 0 || true)
                        {
                            // don't need to account for other drivers
                            var placesAllowed = new Dictionary<int, int>(PointsAwarded);
                            placesAllowed.Remove(1);

                            var result = new Combinations<int>(placesAllowed.Keys.ToList(), RacesToGo, GenerateOption.WithRepetition);

                            var iter = result.GetEnumerator();
                            int pointsAllWin = PointsAwarded[1] * RacesToGo;
                            while (iter.MoveNext())
                            {
                                int pointsHighestDriver = GetPoints(iter.Current);
                                if ((pointsAllWin - pointsHighestDriver) > pointsDifference)
                                {
                                    // found a solution
                                    Console.WriteLine(string.Join(",", iter.Current));
                                }
                            }
                        }
                        else
                        {
                            // there are other drivers with more points than us, so we need to account for them
                        }
                    }
                    else
                    {
                        throw new CalculateException("Not enough points available to win.");
                    }
                }
                else
                {
                    // we're already the highest standing driver, check what we need to do to maintain that
                }
            }
            else
            {
                throw new CalculateException("Driver does not exist.");
            }
        }

        public int GetPoints(IList<int> items)
        {
            return items.Sum(x => PointsAwarded[x]);
        }
    }
}
